﻿using System;
using System.Text;
using TI_BLE_HCI_ClientLib.BaseEntities;
using TI_BLE_HCI_ClientLib.GenericHCIEntities;
using TI_BLE_HCI_ClientLib.HCIBaseEntities;

namespace TI_BLE_HCI_ClientLib.HCICommands
{
    public class HCICommand_GATT_Read_By_Type_Response : HCIVendorSpecificCommand
    {
        private const byte CMD = 0x09;

        public HCICommand_GATT_Read_By_Type_Response(ushort connHandle, byte length, byte[] attrData)
            : base(HCIVendorSpecificCommandCSG.ATT, CMD)
        {
            var pars = new BaseEntityParameter[3];

            pars[0] = new WordParameter(connHandle);
            pars[1] = new ByteParameter(length);
            pars[2] = new ByteArrayParameter(attrData);

            base.addParameters(pars);
        }

        public HCICommand_GATT_Read_By_Type_Response(ushort connHandle, AttributeData[] attrDataArray)
            : this(connHandle, getAttributeDataLength(attrDataArray), getAttributeDataArray(attrDataArray))
        { }


        static byte getAttributeDataLength(AttributeData[] attrDataArray)
        {
            if (attrDataArray == null || attrDataArray.Length == 0) return 0;

            byte len = attrDataArray[0].Length;

            for (int i = 0; i < attrDataArray.Length; i++)
            {
                if(attrDataArray[i].Length!=len)
                {
                    throw new ArgumentException("AttributeDataArray item length is not the same for each item");
                }
            }

            return len;
        }

        static byte[] getAttributeDataArray(AttributeData[] attrDataArray)
        {
            if (attrDataArray == null || attrDataArray.Length == 0) return new byte[0];

            byte attrDataLen = attrDataArray[0].Length;

            var buf = new byte[attrDataArray.Length * attrDataLen];

            for (int i = 0; i < attrDataArray.Length; i++)
            {
                Array.Copy(attrDataArray[i].ToByteArray(), 0, buf, i * attrDataLen, attrDataLen);
            }

            return buf;
        }

        public class AttributeData
        {
            ushort _attributeHandle;
            byte[] _attributeValue;

            public AttributeData(ushort attributeHandle, byte[] attributeValue)
            {
                _attributeHandle = attributeHandle;
                _attributeValue = attributeValue;
            }

            [Flags]
            public enum CharacteristicDeclarationPropertiesEnum : byte
            {
                Broadcast=0x01,
                Read=0x02,
                WriteWithoutResponse=0x04,
                Write=0x08,
                Notify=0x10,
                Indicate=0x20,
                AuthenticatedSignedWrites=0x40,
                ExtendedProperties=0x80
            }

            public AttributeData(ushort attributeHandle, CharacteristicDeclarationPropertiesEnum properties, ushort characteristicHandle, ushort characteristicUUID)
            {
                _attributeHandle = attributeHandle;
                _attributeValue = new byte[5];

                _attributeValue[0] = (byte)properties;
                _attributeValue[1] = (byte)(characteristicHandle & 0xFF);
                _attributeValue[2] = (byte)((characteristicHandle>>8) & 0xFF);
                _attributeValue[3] = (byte)(characteristicUUID & 0xFF);
                _attributeValue[4] = (byte)((characteristicUUID >> 8) & 0xFF);
            }

            public AttributeData(ushort attributeHandle, CharacteristicDeclarationPropertiesEnum properties, ushort characteristicHandle, byte[] characteristicUUID)
            {
                if (characteristicUUID.Length != 2 && characteristicUUID.Length != 16) throw new ApplicationException("characteristicUUID.Length!=2 or 16");

                _attributeHandle = attributeHandle;
                _attributeValue = new byte[3 + characteristicUUID.Length];

                _attributeValue[0] = (byte)properties;
                _attributeValue[1] = (byte)(characteristicHandle & 0xFF);
                _attributeValue[2] = (byte)((characteristicHandle >> 8) & 0xFF);

                Array.Copy(characteristicUUID, 0, _attributeValue, 3, characteristicUUID.Length);
            }

            public byte Length
            {
                get
                {
                    return (byte)(_attributeValue.Length + 2);
                }
            }

            public byte[] ToByteArray()
            {
                var buf = new byte[4 + _attributeValue.Length];

                buf[0] = (byte)(_attributeHandle & 0xFF);
                buf[1] = (byte)((_attributeHandle >> 8) & 0xFF);

                Array.Copy(_attributeValue, 0, buf, 2, _attributeValue.Length);

                return buf;
            }
        }
    }
}
